#ifndef	_NESTER_H_
#define	_NESTER_H_

#include <vector>
#include <algorithm>
#include <string>
#include <iterator>

#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/math/constants/constants.hpp>

#include <CGAL/Timer.h>

#include <Geex/basics/types.h>
#include <glut_viewer/glut_viewer.h>

#include "../common/particle_circle.h"
#include "../common/containers.h"
//#include "../common/potential_energy.h"
#include "../common/circle_union.h"
#include "../common/circle_system.h"
#include "discrete_circle_system.h"


namespace Particle_packing 
{

	using namespace Geex;
	using namespace Packing_common;

	class Particle_packing_graphics;

	class Particle_packer 
	{
		//typedef boost::shared_ptr<Geex::Polygon_2> PolygonPrt;
		friend class Particle_packing_graphics;

	public:
		
		Particle_packer(const std::string& circle_fn, bool circle_union = false) ;
		~Particle_packer();
		/* set methods */
	
		/* query methods */
		static Particle_packer* instance() { return instance_ ; }

		/* debug */
		
		/* computation */
		double energy_minimize();
		void perturb() ;
		void pack(unsigned int nb_trials = 50);
		void shuffle();
		//unsigned int nb_particles() const { return circles.size() - 1; }
		/* miscellaneous */
		void get_bbox(Geex::real& x_min, Geex::real& y_min, Geex::real& z_min, Geex::real& x_max, Geex::real& y_max, Geex::real& z_max);

	private:
		static Particle_packer* instance_ ;

		Rectangular_box *rbox;

		double min_energy;
		// circle packing
		std::vector<Particle_circle> circles;
		std::vector<Particle_circle> best_config;
		// circle union packing
		std::vector<Circle_union> circle_unions;

		boost::random::mt19937 rand_gen;
	} ;


}

#endif